GSoC23 — Workweek 6

Introduction

This week I worked on polishing PR #966. Besides that I worked on including the specify blocks to the PDK, which is already working quite well. Probably next week I will create a PR in open_pdks for that, but I still need to check a few things. I am also working on the next big feature, SDF INTERCONNECT, which has two sides to it: the VPI side and the VVP side.

Improve Parsing of Timing Checks

The issue with timing checks is that $setuphold and $recrem are one of the few statements in Verilog where you can specify varying numbers of optional parameters with different data types. In my previous implementation this was not handled very well which resulted in shift/reduce conflicts. Still, the parsing was succesfull because Bison chooses to shift upon conflicts.

This issue has now been properly fixed, which means any of the following statements is parsed correctly, and everything in between.

No optional arguments:

$setuphold(posedge CLK, posedge D, 0:0:0, 0:0:0);

All optional arguments:

$setuphold(posedge CLK, posedge D, 0:0:0, 0:0:0, notifier, COND0, COND0, CLK_delayed, D_delayed);

Empty optional arguments:

$setuphold(posedge CLK, posedge D, 0:0:0, 0:0:0, , , , , );

And anything in between:

$setuphold(posedge CLK, posedge D, 0:0:0, 0:0:0, notifier, , COND0, , D_delayed);

Another small fix: The conditions can not only be signal names, but expressions too. This fixes parsing the sky130_fd_io cell library.

Based on the feedback I got, I fixed some issues in my code, mainly using more C++11 features.

Interconnect - The VPI side

VPI stands for Verification Procedural Interface and is part of the Programming Language Interface (PLI). It allows you to define system task in your C code that can be loaded into the simulator as a module. Subsequently, these system tasks can be used from within your (System)Verilog code.

Not by chance, the SDF annotator is also just a VPI module and uses the VPI API to access the design and to put delays. This is done via the $sdf_annotate(...) system task.

For my next step, I researched what will be required on the VPI side to implement the SDF INTERCONNECT feature. Here are my findings so far.

Icarus Verilog needs to support the vpiInterModPath object. It is described as an intermodule wire delay, exactly what we need.

Also vpi_handle_multi() must be implemented to get a handle to a vpiInterModPath, like this:

vpi_handle_multi(vpiInterModPath, port1, port2);

The question is how we can get the ports by their names in the SDF file?

  1. Get ports by name

We could use vpi_handle_by_name(name, scope), but the standard says that since a port does not have a full name it cannot be found by name.

  1. Get ports by iterating over all vpiPort objects of a module

So we simply get all ports via itr = vpi_iterate(vpiPort, module). But over which module do we iterate? The INTERCONNECT statement contains the hierarchical path to the ports as seen by the current module.

    (INTERCONNECT A submodule.B (0:0:0) (0:0:0))

So port A of the current module is connected to port B of submodule. Therefore, we first get the handle to the correct module and then iterate over the ports.

While iterating over the ports we check if a port has been found with the correct name and width.

If so we get the handle to the intermodpath via vpi_handle_multi(vpiInterModPath, port1, port2); and put our delays with vpi_put_delays().

So much from the VPI side ;)

Interconnect - The VVP side

Where do we start on the VVP side? When vpi_handle_multi(vpiInterModPath, port1, port2); is called we first must verify that the supplied ports are connected to the same net. How to do this I am not sure yet.

The idea is, once we know the net for the two ports, we insert a vvp_fun_delay in between. The InterModPath object we create has references to the ports, the net and the delay element. If an output port drives multiple input ports, the net needs to be split into multiple nets.

Here mod1.A is connected to mod2.B and mod3.C.

mod1             mod2
===|            |===
   |      |-----| B
   | net1 |     |===
 A |------|
   |      |     |===
   |      |-----| C
===|            |===
                 mod3

The following statement wants to insert a delay from mod1.A -> mod2.B.

    (INTERCONNECT mod1.A mod2.B (0:0:0) (0:0:0))

Therefore we split up the net into two and insert the delay into the new net.

mod1                     mod2
===|              net2  |===
   |      |-delay-------| B
   | net1 |             |===
 A |------|
   |      |     |===
   |      |-----| C
===|            |===
                 mod3

Finally, we would set the interconnect delays via vpi_put_delays() and to support incremental delays we would also need to support vpi_get_delays().

Summary

That's it for this week. Next week I hope to open a PR in open_pdks for the specify blocks and also to start with the implementation of the VPI side of SDF INTERCONNECT.

See you!